package ee.propaganda.gparrot.server;

import java.util.List;
import java.util.Vector;

import javax.jdo.JDOHelper;
import javax.jdo.PersistenceManager;
import javax.jdo.PersistenceManagerFactory;
import javax.jdo.Query;

import com.google.appengine.api.users.User; 
import com.google.appengine.api.users.UserService; 
import com.google.appengine.api.users.UserServiceFactory;
import com.google.gwt.user.server.rpc.RemoteServiceServlet;
import ee.propaganda.gparrot.server.ServiceEntity;
import ee.propaganda.gparrot.client.app.ajax.NotLoggedInException;
import ee.propaganda.gparrot.client.model.DataService;
import ee.propaganda.gparrot.client.model.LoginInfo;
import ee.propaganda.gparrot.client.model.ServiceInfo;

@SuppressWarnings("serial")
public class DataServiceImpl extends RemoteServiceServlet implements DataService {
	private static final PersistenceManagerFactory PMF = 
		JDOHelper.getPersistenceManagerFactory("transactions-optional");
	
	
	@Override
	public Vector<ServiceInfo> update(LoginInfo loginInfo, ServiceInfo si) throws NotLoggedInException {
		
		// ensure that the current user is logged in 
		checkLoggedIn();
		// create an entity from front-end datamodel class
		ServiceEntity serviceEntity = new ServiceEntity();
		serviceEntity.setServiceAccessToken(si.getAccessToken());
		serviceEntity.setServiceType(si.getServiceType());
		serviceEntity.setUserEmail(loginInfo.getEmailAddress());
		
		PersistenceManager pm = getPersistenceManager(); 
		try {
			//check if it is an update, get reference to previously persisted entity
			ServiceEntity se = getService(loginInfo, serviceEntity);
			if(se != null){
				//if it is an update, assign new values to persistent entity
				se.setServiceAccessToken(serviceEntity.getServiceAccessToken());
				se.setServiceType(serviceEntity.getServiceType());
				se.setUserEmail(serviceEntity.getUserEmail());
				serviceEntity = se;
			}
			//persist the entity
			pm.makePersistent(serviceEntity); 
		} finally { 
			pm.close(); 
		}
		return getServices(loginInfo);
	}
	
	//helper method to get reference to persisted entity
	@SuppressWarnings("unchecked")
	private ServiceEntity getService (LoginInfo loginInfo, ServiceEntity serviceEntity){
		List<ServiceEntity> serviceEntityToReturn = null;
		PersistenceManager pm2 = getPersistenceManager();
		try { 
			//String query = "select from ConnectedServiceEntity where userEmail == '"+ getUser().getEmail() 
			//+"' && serviceType == '" + serviceEntity.getServiceType() + "'";
			
			Query q = pm2.newQuery(ServiceEntity.class);
			q.setFilter("userEmail == '"+ getUser().getEmail() 
			+"' && serviceType == '" + serviceEntity.getServiceType() + "'");
			serviceEntityToReturn = (List<ServiceEntity>) pm2.newQuery(q).execute();
			if(serviceEntityToReturn.iterator().hasNext())
				return serviceEntityToReturn.iterator().next();
			else
				return null;	    
		} finally { 
			pm2.close(); 
		} 
		
	}
	
	
	
	@SuppressWarnings("unchecked")
	@Override
	public Vector<ServiceInfo> getServices(LoginInfo loginInfo) throws NotLoggedInException { 
	    
		// ensure that the current user is logged in 
		checkLoggedIn(); 
	   
		Vector<ServiceInfo> services = new Vector<ServiceInfo>(); 
	   
		PersistenceManager pm = getPersistenceManager(); 
		try { 
			String query = "select from " + 
			ServiceEntity.class.getName() + " where userEmail == '"+ getUser().getEmail() 
			+"'"; 
			List<ServiceEntity> entities = (List<ServiceEntity>) pm.newQuery(query).execute();
			for (ServiceEntity entity : entities) { 
				ServiceInfo si = new ServiceInfo(entity.getServiceAccessToken(), entity.getServiceType()); 
				services.add(si); 
			} 
	    
		} finally { 
			pm.close(); 
		} 
	   
		return services;   
	}
	
	//returns persistence manager singleton instance
	private PersistenceManager getPersistenceManager() { 
		 return PMF.getPersistenceManager(); 
	}
	
	// returns the current user from Google Accounts 
	private User getUser() { 
		UserService userService = UserServiceFactory.getUserService(); 
		return userService.getCurrentUser(); 
	} 
	  
	// determines if the user is currently logged in. If not, throws an exception. 
	private void checkLoggedIn() throws NotLoggedInException { 
		if (getUser() == null)  
			throw new NotLoggedInException("User not logged in. Please login with your Google Accounts credentials."); 
	}

	@Override
	public void updateAll(LoginInfo loginInfo, 
			Vector<ServiceInfo> registeredServices) throws NotLoggedInException {
		for (ServiceInfo serviceInfo : registeredServices) {
			update(loginInfo, serviceInfo);
		}
	}

}
